package com.mipssa;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import java.math.BigInteger;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

public class Util {

	static public Map<String, Instruccion> cargarArchivoInstrucciones()
	{
		Map<String, Instruccion> instrucciones = new HashMap<String, Instruccion>();
		String nombre = "";
		String opcode = "";
		String sintaxis = "";
		
		
		try{    
			/* para ejecutar en .jar */
			InputStream is = Util.class.getClassLoader().getResourceAsStream("com/mipssa/opcodes/opcodes.txt");
			    
			/* para ejecutar en elipse comentar linea de arriba
			 * y reestablecer la linea de abajo.*/
			// FileInputStream is = new FileInputStream("opcodes/opcodes.txt");
			
			  DataInputStream in = new DataInputStream(is);
			  BufferedReader br = new BufferedReader(new InputStreamReader(in));
			  String strLine;
			  //Read File Line By Line
			  while ((strLine = br.readLine()) != null)   {
			  
				  if (strLine.length() != 0 && !strLine.startsWith("#") && esUnaLetra(strLine.charAt(0)))
				  {
					  String sub = "";
					  String sint = "";
					  nombre = strLine.substring(0, strLine.indexOf(';'));
					  sub = strLine.substring(strLine.indexOf("\"")+1);
					  sub = sub.substring(0,sub.indexOf("\""));
					  opcode = sub;					  
					  
					  sint = strLine.split(";")[2];
					  sint = sint.split("\"")[1];
					  
					  Instruccion instr = new Instruccion(nombre,opcode,sint);
					  instrucciones.put(nombre, instr);
					  
				  }
				  // Print the content on the console
				  //System.out.println (strLine);
			  }
			  //Close the input stream
			  is.close();
			  in.close();
			    }catch (Exception e){//Catch exception if any
			  System.err.println("Error: " + e.getMessage());
			  }
			    
			    
		
		return instrucciones;
	}
	
	public static boolean esUnaLetra(char car)
	{
		String letras = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
		int i;
				
		for(i=0;i< letras.length();i++)
		{
			if(car == letras.charAt(i))
			{
				return true;
			}
			
		}
		
		return false;
	}
	
	public static Vector<String> cargarArchivoAsm(String nombre)
	{
		Vector<String> archAsm = new Vector<String>();
		
		try{
			  // Open the file that is the first 
			  // command line parameter
			  FileInputStream fstream = new FileInputStream(nombre);
			  // Get the object of DataInputStream
			  DataInputStream in = new DataInputStream(fstream);
			  BufferedReader br = new BufferedReader(new InputStreamReader(in));
			  String strLine;
			  //Read File Line By Line
			  while ((strLine = br.readLine()) != null)   {
			  
				 archAsm.addElement(strLine);
				  // Print the content on the console
				  //System.out.println (strLine);
			  }
			  //Close the input stream
			  in.close();
			    }catch (Exception e){//Catch exception if any
			  //System.err.println("Error: " + e.getMessage());
			  System.out.println("\nERROR! No se puede abrir el archivo \""+nombre+"\"");
			  System.exit(0);
			  }
		
		return archAsm;
	}
	
	/* convierte enteros a string binario, se rellena con ceros de acuerdo a tam */
	public static String enteroABinario(Integer num, int tam)
	{
		String numero = "";
		if (num >=0) 
		{
			numero = String.format("%0" + tam + "d",
					new BigInteger(Integer.toBinaryString(num)));
		}
		else
		{
			numero = String.format("%0" + tam + "d",
					new BigInteger(Integer.toBinaryString(num)));
			numero = numero.substring(16); /* elimino los 16 primeros bits */
		}
		return numero;
	}
	
	public static String longABinario(Long num, int tam)
	{
		String numero = "";
		if (num >=0) 
		{
			numero = String.format("%0" + tam + "d",
					new BigInteger(Long.toBinaryString(num)));
		}
		else
		{
			numero = String.format("%0" + tam + "d",
					new BigInteger(Long.toBinaryString(num)));
			numero = numero.substring(16); /* elimino los 16 primeros bits */
		}
		return numero;
	}
	
	public static Integer getOffsetFromLabel(Integer direcLabel,Integer direc)
	{
		Integer offset = 0;
		if(direcLabel<direc)
		{
			offset = -(direc - direcLabel)-1;
		}
		else
		{
			offset = (direcLabel - direc)-1;
		}
		return offset;
		
	}
	/*
	 * Tipo: coe/mif
	 * radix: hex/bin
	 */
	public static int crearArchivo(Vector<Long> contenido, String nombre, String tipo)
	{
		int retVal = 0;
		int i;
		String salidaArchivo = "";
		Writer output;
		File arch;
		if(tipo.equals("mif"))
		{
			arch = new File(nombre+".mif");
		}
		else
		{
			arch = new File(nombre+".coe");

		}
	
		
		if(tipo.equals("coe"))
		{
			salidaArchivo = salidaArchivo.concat("memory_initialization_radix=16;\n");
			salidaArchivo = salidaArchivo.concat("memory_initialization_vector=\n");
		}
		

		
		
		for(i=0; i<contenido.size();i++)
		{
			Long valor = contenido.elementAt(i);
			String opcode;
			if(tipo.equals("coe"))
			{
				opcode = String.format("%08x", valor);
				
				salidaArchivo = salidaArchivo.concat(opcode);
				if(i == (contenido.size()-1))
				{
					salidaArchivo = salidaArchivo+";\n";
				}
				else
				{
					salidaArchivo = salidaArchivo+",\n";
				}
			}
			else
			{
				opcode = longABinario(valor,32);
				salidaArchivo = salidaArchivo.concat(opcode);
				salidaArchivo = salidaArchivo+"\n";
				//opcode = Long.toBinaryString(valor);
			}
			
			
		}
		
		  try {
			output = new BufferedWriter(new FileWriter(arch));
			  output.write(salidaArchivo);
			  output.close();
			  System.out.println("\nOk! Se creo el archivo \""+arch.getName()+"\"");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println("\n Error! No se pudo crear el archivo \""+arch.getName()+"\"");
			//e.printStackTrace();
			retVal = -1;
		}
		
		
		return retVal;
	}
}
